using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using TileEngine;
using System.Windows.Forms;

namespace LevelEditor
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        IntPtr drawSurface;
        System.Windows.Forms.Form parentForm;
        System.Windows.Forms.PictureBox pictureBox;
        System.Windows.Forms.Control gameForm;

        public int DrawLayer = 0;
        public int DrawTile = 0;
        public int currentTileRotation = 0;
        public string tileName = "";
        
        //name of tiletexture
        public static string defaulttileSheetName = "tiles3";
        public List<Texture2D> tileSheets = new List<Texture2D>();
        public Texture2D currentTileSheet;

        public List<MapSquare> selectedTiles = new List<MapSquare>();
        MapSquare currentTileHover = null;

        public bool canDraw = true;
        public bool SelectTileMode = false;

        public MouseState lastMouseState;
        public int oldScrollWheelValue;

        System.Windows.Forms.VScrollBar vscroll;
        System.Windows.Forms.HScrollBar hscroll;

        public Game1(IntPtr drawSurface,
                    System.Windows.Forms.Form parentForm,
                    System.Windows.Forms.PictureBox surfacePictureBox)
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            this.drawSurface = drawSurface;
            this.parentForm = parentForm;
            this.pictureBox = surfacePictureBox;

            graphics.PreparingDeviceSettings +=
                new EventHandler<PreparingDeviceSettingsEventArgs>(
                graphics_PreparingDeviceSettings);

            Mouse.WindowHandle = drawSurface;

            gameForm =
                System.Windows.Forms.Control.FromHandle(this.Window.Handle);
            gameForm.VisibleChanged += new EventHandler(gameForm_VisibleChanged);
            pictureBox.SizeChanged += new EventHandler(pictureBox_SizeChanged);

            vscroll =
                (System.Windows.Forms.VScrollBar)parentForm.Controls["vScrollBar1"];
            hscroll =
                (System.Windows.Forms.HScrollBar)parentForm.Controls["hScrollBar1"];

        }

        void graphics_PreparingDeviceSettings(object sender,
            PreparingDeviceSettingsEventArgs e)
        {

            e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = drawSurface;

        }

        private void gameForm_VisibleChanged(object sender, EventArgs e)
        {
            if (gameForm.Visible == true)
                gameForm.Visible = false;
        }

        void pictureBox_SizeChanged(object sender, EventArgs e)
        {
            if (parentForm.WindowState !=
                System.Windows.Forms.FormWindowState.Minimized)
            {
                graphics.PreferredBackBufferWidth = pictureBox.Width;
                graphics.PreferredBackBufferHeight = pictureBox.Height;
                Camera.ViewPortWidth = pictureBox.Width;
                Camera.ViewPortHeight = pictureBox.Height;
                graphics.ApplyChanges();
            }
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Camera.ViewPortWidth = pictureBox.Width;
            Camera.ViewPortHeight = pictureBox.Height;
            Camera.WorldRectangle =
                new Rectangle(
                    0,
                    0,
                    TileMap.TileWidth * TileMap.MapWidth,
                    TileMap.TileHeight * TileMap.MapHeight
                );
            tileSheets.Add(Content.Load<Texture2D>(@"textures\tilesheets\" + defaulttileSheetName));
            tileSheets.Add(Content.Load<Texture2D>(@"textures\tilesheets\editorTiles"));

            TileMap.Initialize(tileSheets);
         
            TileMap.spriteFont =
                Content.Load<SpriteFont>(@"fonts\Arial");

            lastMouseState = Mouse.GetState();
            oldScrollWheelValue = lastMouseState.ScrollWheelValue;

            pictureBox_SizeChanged(null, null);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        private bool IsControlAtFront(Control control)
        {
           
            while (control.Parent != null)
            {
                if (control.Parent.Controls.GetChildIndex(control) == 0)
                {
                    Console.WriteLine("test");
                    control = control.Parent;
                    if (control.Parent == null)
                    {
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            }
            return false;
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;            

            Camera.Position = new Vector2(hscroll.Value, vscroll.Value);

            MouseState ms = Mouse.GetState();
            KeyboardState kbs = Keyboard.GetState();

            if ((ms.X > 0) && (ms.Y > 0) &&
                (ms.X < Camera.ViewPortWidth) &&
                (ms.Y < Camera.ViewPortHeight))
            {
                Vector2 mouseLoc = Camera.ScreenToWorld(
                    new Vector2(ms.X, ms.Y));


                if (pictureBox.Capture)
                {
                    canDraw = true;
                }
                
                if (canDraw)
                {                                    
                    if (Camera.WorldRectangle.Contains(
                        (int)mouseLoc.X, (int)mouseLoc.Y))
                    {
                        currentTileHover = TileMap.GetMapSquareAtCell(
                            TileMap.GetCellByPixelX((int)mouseLoc.X),
                            TileMap.GetCellByPixelY((int)mouseLoc.Y)
                        );

                        if (ms.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                        {                          
                            TileMap.SetTileAtCell(
                                TileMap.GetCellByPixelX((int)mouseLoc.X),
                                TileMap.GetCellByPixelY((int)mouseLoc.Y),
                                DrawLayer,
                                DrawTile,
                                tileName);

                            if (kbs.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl))
                            {
                                currentTileHover.m_blocked = true;
                            }
                        }

                        if (kbs.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.LeftControl))
                        {
                            if ((ms.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)) //&&
                            //(lastMouseState.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Released))
                            {
                                if (SelectTileMode)
                                {
                                    if (!currentTileHover.m_selected)
                                    {
                                        selectedTiles.Add(currentTileHover);
                                        //currentTileHover.ToggleSelected();
                                        currentTileHover.m_selected = true;
                                    }
                                }
                                else
                                {
                                    currentTileHover.ToggleBlocked();
                                }
                            }
                        }

                        if (kbs.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl))
                        {
                            if ((ms.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed) &&
                                (lastMouseState.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Released))
                            {
                                if (SelectTileMode)
                                {
                                    selectedTiles.Add(currentTileHover);
                                    currentTileHover.ToggleSelected();
                                    //currentTileHover.m_selected = true;
                                }
                            }
                        }
                        

                        if (lastMouseState.MiddleButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                        {
                            if (selectedTiles.Count > 0)
                            {
                                foreach (MapSquare tile in selectedTiles)
                                {
                                    tile.m_selected = false;
                                }
                                selectedTiles.RemoveRange(0, selectedTiles.Count);
                            }
                        }

                        if ((ms.MiddleButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed) &&
                            (lastMouseState.MiddleButton == Microsoft.Xna.Framework.Input.ButtonState.Released))
                        {
                            if (selectedTiles.Count == 0)                           
                            {                                
                                TileMap.ClearTile((int)mouseLoc.X, (int)mouseLoc.Y);                                
                            }                                                  
                        }
                    }
                }
            }

            lastMouseState = ms;

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin(
                SpriteSortMode.BackToFront,
                BlendState.AlphaBlend);
            TileMap.Draw(spriteBatch);
            spriteBatch.End();

            base.Draw(gameTime);
        }

    }
}
